package simpledb;

import java.io.IOException;

/**
 * Inserts tuples read from the child operator into the tableId specified in the
 * constructor
 * 执行插入操作的类
 * 给定一个元组迭代器，TransactionId标记操作页面为dirty
 * fetchNext()中调用HeapFile中的insert()操作，逐个插入迭代器中每个元组
 */
public class Insert extends Operator {

    private static final long serialVersionUID = 1L;

    private OpIterator child;
    private TransactionId tid;
    private int tableId;
    private TupleDesc tupleDesc;
    //表明该Insert操作是否被访问，默认为false,只允许使用一次
    private boolean hasAccessed;
    /**
     * Constructor.
     *
     * @param tid
     *            The transaction running the insert.
     * @param child
     *            The child operator from which to read tuples to be inserted.
     * @param tableId
     *            The table in which to insert tuples.
     * @throws DbException
     *             if TupleDesc of child differs from table into which we are to
     *             insert.
     */
    public Insert(TransactionId tid, OpIterator child, int tableId)
            throws DbException {
        // some code goes here
        this.child = child;
        this.tid = tid;
        this.tableId = tableId;
        tupleDesc = new TupleDesc(new Type[]{Type.INT_TYPE}, new String[]{null});
        hasAccessed = false;
    }

    public TupleDesc getTupleDesc() {
        // some code goes here
        return tupleDesc;
    }

    public void open() throws DbException, TransactionAbortedException {
        // some code goes here
        super.open();
        child.open();
    }

    public void close() {
        // some code goes here
        child.close();
    }

    public void rewind() throws DbException, TransactionAbortedException {
        // some code goes here
        child.rewind();
    }

    /**
     * Inserts tuples read from child into the tableId specified by the
     * constructor. It returns a one field tuple containing the number of
     * inserted records. Inserts should be passed through BufferPool. An
     * instances of BufferPool is available via Database.getBufferPool(). Note
     * that insert DOES NOT need check to see if a particular tuple is a
     * duplicate before inserting it.
     *
     * @return A 1-field tuple containing the number of inserted records, or
     *         null if called more than once.
     * @see Database#getBufferPool
     * @see BufferPool#insertTuple
     * fetchNext()表示一次将迭代器所有元素都插入
     * 返回插入的行数
     */
    protected Tuple fetchNext() throws TransactionAbortedException, DbException {
        // some code goes here
        if(hasAccessed)
            return null;
        int insertNums = 0;
        while(child.hasNext())
        {
            Tuple tuple = child.next();
            try {
                Database.getBufferPool().insertTuple(tid,tableId,tuple);
            } catch (IOException e) {
                e.printStackTrace();
            }
            insertNums++;
        }
        Tuple return_tup = new Tuple(tupleDesc);
        return_tup.setField(0,new IntField(insertNums));
        hasAccessed = true;
        return return_tup;
    }

    @Override
    public OpIterator[] getChildren() {
        // some code goes here
        return new OpIterator[]{child};
    }

    @Override
    public void setChildren(OpIterator[] children) {
        // some code goes here
        child = children[0];
    }
}
